home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Python / thread_sgi.h < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-03  |  12.1 KB  |  503 lines

  1. #ifdef WITH_SGI_DL
  2. #define USE_DL
  3. #endif
  4.  
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <signal.h>
  8. #include <sys/types.h>
  9. #include <sys/wait.h>
  10. #include <sys/prctl.h>
  11. #include <ulocks.h>
  12. #include <errno.h>
  13.  
  14. #define HDR_SIZE    2680    /* sizeof(ushdr_t) */
  15. #define MAXPROC        100    /* max # of threads that can be started */
  16.  
  17. static usptr_t *shared_arena;
  18. static ulock_t count_lock;    /* protection for some variables */
  19. static ulock_t wait_lock;    /* lock used to wait for other threads */
  20. static int waiting_for_threads;    /* protected by count_lock */
  21. static int nthreads;        /* protected by count_lock */
  22. static int exit_status;
  23. #ifndef NO_EXIT_PROG
  24. static int do_exit;        /* indicates that the program is to exit */
  25. #endif
  26. static int exiting;        /* we're already exiting (for maybe_exit) */
  27. static pid_t my_pid;        /* PID of main thread */
  28. static struct pidlist {
  29.     pid_t parent;
  30.     pid_t child;
  31. } pidlist[MAXPROC];    /* PIDs of other threads; protected by count_lock */
  32. static int maxpidindex;        /* # of PIDs in pidlist */
  33.  
  34. #ifndef NO_EXIT_PROG
  35. /*
  36.  * This routine is called as a signal handler when another thread
  37.  * exits.  When that happens, we must see whether we have to exit as
  38.  * well (because of an PyThread_exit_prog()) or whether we should continue on.
  39.  */
  40. static void exit_sig _P0()
  41. {
  42.     d2printf(("exit_sig called\n"));
  43.     if (exiting && getpid() == my_pid) {
  44.         d2printf(("already exiting\n"));
  45.         return;
  46.     }
  47.     if (do_exit) {
  48.         d2printf(("exiting in exit_sig\n"));
  49. #ifdef Py_DEBUG
  50.         if ((thread_debug & 8) == 0)
  51.             thread_debug &= ~1; /* don't produce debug messages */
  52. #endif
  53.         PyThread_exit_thread();
  54.     }
  55. }
  56.  
  57. /*
  58.  * This routine is called when a process calls exit().  If that wasn't
  59.  * done from the library, we do as if an PyThread_exit_prog() was intended.
  60.  */
  61. static void maybe_exit _P0()
  62. {
  63.     dprintf(("maybe_exit called\n"));
  64.     if (exiting) {
  65.         dprintf(("already exiting\n"));
  66.         return;
  67.     }
  68.     PyThread_exit_prog(0);
  69. }
  70. #endif /* NO_EXIT_PROG */
  71.  
  72. /*
  73.  * Initialization.
  74.  */
  75. static void PyThread__init_thread _P0()
  76. {
  77. #ifndef NO_EXIT_PROG
  78.     struct sigaction s;
  79. #endif /* NO_EXIT_PROG */
  80. #ifdef USE_DL
  81.     long addr, size;
  82. #endif /* USE_DL */
  83.  
  84.  
  85. #ifdef USE_DL
  86.     if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
  87.         perror("usconfig - CONF_INITSIZE (check)");
  88.     if (usconfig(CONF_INITSIZE, size) < 0)
  89.         perror("usconfig - CONF_INITSIZE (reset)");
  90.     addr = (long) dl_getrange(size + HDR_SIZE);
  91.     dprintf(("trying to use addr %lx-%lx for shared arena\n", addr, addr+size));
  92.     errno = 0;
  93.     if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
  94.         perror("usconfig - CONF_ATTACHADDR (set)");
  95. #endif /* USE_DL */
  96.     if (usconfig(CONF_INITUSERS, 16) < 0)
  97.         perror("usconfig - CONF_INITUSERS");
  98.     my_pid = getpid();    /* so that we know which is the main thread */
  99. #ifndef NO_EXIT_PROG
  100.     atexit(maybe_exit);
  101.     s.sa_handler = exit_sig;
  102.     sigemptyset(&s.sa_mask);
  103.     /*sigaddset(&s.sa_mask, SIGUSR1);*/
  104.     s.sa_flags = 0;
  105.     sigaction(SIGUSR1, &s, 0);
  106.     if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
  107.         perror("prctl - PR_SETEXITSIG");
  108. #endif /* NO_EXIT_PROG */
  109.     if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
  110.         perror("usconfig - CONF_ARENATYPE");
  111.     usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
  112. #ifdef Py_DEBUG
  113.     if (thread_debug & 4)
  114.         usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
  115.     else if (thread_debug & 2)
  116.         usconfig(CONF_LOCKTYPE, US_DEBUG);
  117. #endif /* Py_DEBUG */
  118.     if ((shared_arena = usinit(tmpnam(0))) == 0)
  119.         perror("usinit");
  120. #ifdef USE_DL
  121.     if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
  122.         perror("usconfig - CONF_ATTACHADDR (reset)");
  123. #endif /* USE_DL */
  124.     if ((count_lock = usnewlock(shared_arena)) == NULL)
  125.         perror("usnewlock (count_lock)");
  126.     (void) usinitlock(count_lock);
  127.     if ((wait_lock = usnewlock(shared_arena)) == NULL)
  128.         perror("usnewlock (wait_lock)");
  129.     dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
  130. }
  131.  
  132. /*
  133.  * Thread support.
  134.  */
  135.  
  136. static void clean_threads _P0()
  137. {
  138.     int i, j;
  139.     pid_t mypid, pid;
  140.  
  141.     /* clean up any exited threads */
  142.     mypid = getpid();
  143.     i = 0;
  144.     while (i < maxpidindex) {
  145.         if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
  146.             pid = waitpid(pid, 0, WNOHANG);
  147.             if (pid > 0) {
  148.                 /* a thread has exited */
  149.                 pidlist[i] = pidlist[--maxpidindex];
  150.                 /* remove references to children of dead proc */
  151.                 for (j = 0; j < maxpidindex; j++)
  152.                     if (pidlist[j].parent == pid)
  153.                         pidlist[j].child = -1;
  154.                 continue; /* don't increment i */
  155.             }
  156.         }
  157.         i++;
  158.     }
  159.     /* clean up the list */
  160.     i = 0;
  161.     while (i < maxpidindex) {
  162.         if (pidlist[i].child == -1) {
  163.             pidlist[i] = pidlist[--maxpidindex];
  164.             continue; /* don't increment i */
  165.         }
  166.         i++;
  167.     }
  168. }
  169.  
  170. int PyThread_start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
  171. {
  172. #ifdef USE_DL
  173.     long addr, size;
  174.     static int local_initialized = 0;
  175. #endif /* USE_DL */
  176.     int success = 0;    /* init not needed when SOLARIS_THREADS and */
  177.                 /* C_THREADS implemented properly */
  178.  
  179.     dprintf(("PyThread_start_new_thread called\n"));
  180.     if (!initialized)
  181.         PyThread_init_thread();
  182.     switch (ussetlock(count_lock)) {
  183.     case 0: return 0;
  184.     case -1: perror("ussetlock (count_lock)");
  185.     }
  186.     if (maxpidindex >= MAXPROC)
  187.         success = -1;
  188.     else {
  189. #ifdef USE_DL
  190.         if (!local_initialized) {
  191.             if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
  192.                 perror("usconfig - CONF_INITSIZE (check)");
  193.             if (usconfig(CONF_INITSIZE, size) < 0)
  194.                 perror("usconfig - CONF_INITSIZE (reset)");
  195.             addr = (long) dl_getrange(size + HDR_SIZE);
  196.             dprintf(("trying to use addr %lx-%lx for sproc\n",
  197.                  addr, addr+size));
  198.             errno = 0;
  199.             if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
  200.                 errno != 0)
  201.                 perror("usconfig - CONF_ATTACHADDR (set)");
  202.         }
  203. #endif /* USE_DL */
  204.         clean_threads();
  205.         if ((success = sproc(func, PR_SALL, arg)) < 0)
  206.             perror("sproc");
  207. #ifdef USE_DL
  208.         if (!local_initialized) {
  209.             if (usconfig(CONF_ATTACHADDR, addr) < 0)
  210.                 /* reset address */
  211.                 perror("usconfig - CONF_ATTACHADDR (reset)");
  212.             local_initialized = 1;
  213.         }
  214. #endif /* USE_DL */
  215.         if (success >= 0) {
  216.             nthreads++;
  217.             pidlist[maxpidindex].parent = getpid();
  218.             pidlist[maxpidindex++].child = success;
  219.             dprintf(("pidlist[%d] = %d\n",
  220.                  maxpidindex-1, success));
  221.         }
  222.     }
  223.     if (usunsetlock(count_lock) < 0)
  224.         perror("usunsetlock (count_lock)");
  225.     return success < 0 ? 0 : 1;
  226. }
  227.  
  228. long PyThread_get_thread_ident _P0()
  229. {
  230.     return getpid();
  231. }
  232.  
  233. static void do_PyThread_exit_thread _P1(no_cleanup, int no_cleanup)
  234. {
  235.     dprintf(("PyThread_exit_thread called\n"));
  236.     if (!initialized)
  237.         if (no_cleanup)
  238.             _exit(0);
  239.         else
  240.             exit(0);
  241.     if (ussetlock(count_lock) < 0)
  242.         perror("ussetlock (count_lock)");
  243.     nthreads--;
  244.     if (getpid() == my_pid) {
  245.         /* main thread; wait for other threads to exit */
  246.         exiting = 1;
  247. #ifndef NO_EXIT_PROG
  248.         if (do_exit) {
  249.             int i;
  250.  
  251.             /* notify other threads */
  252.             clean_threads();
  253.             if (nthreads >= 0) {
  254.                 dprintf(("kill other threads\n"));
  255.                 for (i = 0; i < maxpidindex; i++)
  256.                     if (pidlist[i].child > 0)
  257.                         (void) kill(pidlist[i].child,
  258.                                 SIGKILL);
  259.                 _exit(exit_status);
  260.             }
  261.         }
  262. #endif /* NO_EXIT_PROG */
  263.         waiting_for_threads = 1;
  264.         if (ussetlock(wait_lock) < 0)
  265.             perror("ussetlock (wait_lock)");
  266.         for (;;) {
  267.             if (nthreads < 0) {
  268.                 dprintf(("really exit (%d)\n", exit_status));
  269.                 if (no_cleanup)
  270.                     _exit(exit_status);
  271.                 else
  272.                     exit(exit_status);
  273.             }
  274.             if (usunsetlock(count_lock) < 0)
  275.                 perror("usunsetlock (count_lock)");
  276.             dprintf(("waiting for other threads (%d)\n", nthreads));
  277.             if (ussetlock(wait_lock) < 0)
  278.                 perror("ussetlock (wait_lock)");
  279.             if (ussetlock(count_lock) < 0)
  280.                 perror("ussetlock (count_lock)");
  281.         }
  282.     }
  283.     /* not the main thread */
  284.     if (waiting_for_threads) {
  285.         dprintf(("main thread is waiting\n"));
  286.         if (usunsetlock(wait_lock) < 0)
  287.             perror("usunsetlock (wait_lock)");
  288.     }
  289. #ifndef NO_EXIT_PROG
  290.     else if (do_exit)
  291.         (void) kill(my_pid, SIGUSR1);
  292. #endif /* NO_EXIT_PROG */
  293.     if (usunsetlock(count_lock) < 0)
  294.         perror("usunsetlock (count_lock)");
  295.     _exit(0);
  296. }
  297.  
  298. void PyThread_exit_thread _P0()
  299. {
  300.     do_PyThread_exit_thread(0);
  301. }
  302.  
  303. void PyThread__exit_thread _P0()
  304. {
  305.     do_PyThread_exit_thread(1);
  306. }
  307.  
  308. #ifndef NO_EXIT_PROG
  309. static void do_PyThread_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
  310. {
  311.     dprintf(("PyThread_exit_prog(%d) called\n", status));
  312.     if (!initialized)
  313.         if (no_cleanup)
  314.             _exit(status);
  315.         else
  316.             exit(status);
  317.     do_exit = 1;
  318.     exit_status = status;
  319.     do_PyThread_exit_thread(no_cleanup);
  320. }
  321.  
  322. void PyThread_exit_prog _P1(status, int status)
  323. {
  324.     do_PyThread_exit_prog(status, 0);
  325. }
  326.  
  327. void PyThread__exit_prog _P1(status, int status)
  328. {
  329.     do_PyThread_exit_prog(status, 1);
  330. }
  331. #endif /* NO_EXIT_PROG */
  332.  
  333. /*
  334.  * Lock support.
  335.  */
  336. PyThread_type_lock PyThread_allocate_lock _P0()
  337. {
  338.     ulock_t lock;
  339.  
  340.     dprintf(("PyThread_allocate_lock called\n"));
  341.     if (!initialized)
  342.         PyThread_init_thread();
  343.  
  344.     if ((lock = usnewlock(shared_arena)) == NULL)
  345.         perror("usnewlock");
  346.     (void) usinitlock(lock);
  347.     dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock));
  348.     return (PyThread_type_lock) lock;
  349. }
  350.  
  351. void PyThread_free_lock _P1(lock, PyThread_type_lock lock)
  352. {
  353.     dprintf(("PyThread_free_lock(%lx) called\n", (long)lock));
  354.     usfreelock((ulock_t) lock, shared_arena);
  355. }
  356.  
  357. int PyThread_acquire_lock _P2(lock, PyThread_type_lock lock, waitflag, int waitflag)
  358. {
  359.     int success;
  360.  
  361.     dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
  362.     errno = 0;        /* clear it just in case */
  363.     if (waitflag)
  364.         success = ussetlock((ulock_t) lock);
  365.     else
  366.         success = uscsetlock((ulock_t) lock, 1); /* Try it once */
  367.     if (success < 0)
  368.         perror(waitflag ? "ussetlock" : "uscsetlock");
  369.     dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
  370.     return success;
  371. }
  372.  
  373. void PyThread_release_lock _P1(lock, PyThread_type_lock lock)
  374. {
  375.     dprintf(("PyThread_release_lock(%lx) called\n", (long)lock));
  376.     if (usunsetlock((ulock_t) lock) < 0)
  377.         perror("usunsetlock");
  378. }
  379.  
  380. /*
  381.  * Semaphore support.
  382.  */
  383. PyThread_type_sema PyThread_allocate_sema _P1(value, int value)
  384. {
  385.     usema_t *sema;
  386.     dprintf(("PyThread_allocate_sema called\n"));
  387.     if (!initialized)
  388.         PyThread_init_thread();
  389.  
  390.     if ((sema = usnewsema(shared_arena, value)) == NULL)
  391.         perror("usnewsema");
  392.     dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema));
  393.     return (PyThread_type_sema) sema;
  394. }
  395.  
  396. void PyThread_free_sema _P1(sema, PyThread_type_sema sema)
  397. {
  398.     dprintf(("PyThread_free_sema(%lx) called\n", (long) sema));
  399.     usfreesema((usema_t *) sema, shared_arena);
  400. }
  401.  
  402. int PyThread_down_sema _P2(sema, PyThread_type_sema sema, waitflag, int waitflag)
  403. {
  404.     int success;
  405.  
  406.     dprintf(("PyThread_down_sema(%lx) called\n", (long) sema));
  407.     if (waitflag)
  408.         success = uspsema((usema_t *) sema);
  409.     else
  410.         success = uscpsema((usema_t *) sema);
  411.     if (success < 0)
  412.         perror(waitflag ? "uspsema" : "uscpsema");
  413.     dprintf(("PyThread_down_sema(%lx) return\n", (long) sema));
  414.     return success;
  415. }
  416.  
  417. void PyThread_up_sema _P1(sema, PyThread_type_sema sema)
  418. {
  419.     dprintf(("PyThread_up_sema(%lx)\n", (long) sema));
  420.     if (usvsema((usema_t *) sema) < 0)
  421.         perror("usvsema");
  422. }
  423.  
  424. /*
  425.  * Per-thread data ("key") support.
  426.  */
  427.  
  428. struct key {
  429.     struct key *next;
  430.     long id;
  431.     int key;
  432.     void *value;
  433. };
  434.  
  435. static struct key *keyhead = NULL;
  436. static int nkeys = 0;
  437. static PyThread_type_lock keymutex = NULL;
  438.  
  439. static struct key *find_key _P2(key, int key, value, void *value)
  440. {
  441.     struct key *p;
  442.     long id = PyThread_get_thread_ident();
  443.     for (p = keyhead; p != NULL; p = p->next) {
  444.         if (p->id == id && p->key == key)
  445.             return p;
  446.     }
  447.     if (value == NULL)
  448.         return NULL;
  449.     p = (struct key *)malloc(sizeof(struct key));
  450.     if (p != NULL) {
  451.         p->id = id;
  452.         p->key = key;
  453.         p->value = value;
  454.         PyThread_acquire_lock(keymutex, 1);
  455.         p->next = keyhead;
  456.         keyhead = p;
  457.         PyThread_release_lock(keymutex);
  458.     }
  459.     return p;
  460. }
  461.  
  462. int PyThread_create_key _P0()
  463. {
  464.     if (keymutex == NULL)
  465.         keymutex = PyThread_allocate_lock();
  466.     return ++nkeys;
  467. }
  468.  
  469. void PyThread_delete_key _P1(key, int key)
  470. {
  471.     struct key *p, **q;
  472.     PyThread_acquire_lock(keymutex, 1);
  473.     q = &keyhead;
  474.     while ((p = *q) != NULL) {
  475.         if (p->key == key) {
  476.             *q = p->next;
  477.             free((void *)p);
  478.             /* NB This does *not* free p->value! */
  479.         }
  480.         else
  481.             q = &p->next;
  482.     }
  483.     PyThread_release_lock(keymutex);
  484. }
  485.  
  486. int PyThread_set_key_value _P2(key, int key, value, void *value)
  487. {
  488.     struct key *p = find_key(key, value);
  489.     if (p == NULL)
  490.         return -1;
  491.     else
  492.         return 0;
  493. }
  494.  
  495. void *PyThread_get_key_value _P1(key, int key)
  496. {
  497.     struct key *p = find_key(key, NULL);
  498.     if (p == NULL)
  499.         return NULL;
  500.     else
  501.         return p->value;
  502. }
  503.